package cx.ath.skyflyer.chart;

import java.util.Enumeration;
import java.util.Vector;
import javax.microedition.lcdui.Graphics;

/**
 *
 * @author Ahti Legonkov
 */
public class LineChart {

    public LineChart(Rectangle chartRect) {
        this.chartRect = chartRect;
    }

    /**
     * Adds data series to visualize as line chart.
     * @param v
     */
    public void addSeries(DataSeries v) {
        if (!m_Series.contains(v)) {
            m_Series.addElement(v);
        }
    }

    public Enumeration getSeries() {
        return m_Series.elements();
    }

    /**
     * Draws the line chart.
     * @param g - a graphics context to draw on.
     */
    public void draw(Graphics g) {

        Enumeration e = m_Series.elements();
        while (e.hasMoreElements()) {
            DataSeries ds = (DataSeries)e.nextElement();
            drawSeries(g, ds);
        }
    }

    public void setMinXValue(double minXValue) {
        this.minXValue = minXValue;
    }

    public double getMinXValue() { return minXValue; }

    public void setMaxXValue(double maxXValue) {
        this.maxXValue = maxXValue;
    }

    public double getMaxXValue() { return maxXValue; }

    public void setMinYValue(double minYValue) {
        this.minYValue = minYValue;
    }

    public double getMinYValue() { return minYValue; }

    public void setMaxYValue(double maxYValue) {
        this.maxYValue = maxYValue;
    }

    public double getMaxYValue() { return maxYValue; }
    
    public void adjustVerticalRange() {
        Enumeration e = m_Series.elements();
        DataPoint min = null;
        DataPoint max = null;
        while (e.hasMoreElements()) {
            DataSeries ds = (DataSeries)e.nextElement();

            DataPoint pt = ds.maxY(minXValue, maxXValue);
            if (max == null || pt.y > max.y)
                max = pt;

            pt = ds.minY(minXValue, maxXValue);
            if (min == null || pt.y < min.y)
                min = pt;
        }

        if (min == null || max == null)
            return;

        double diff = max.y - min.y;
        double extra = 0.05 * diff;

        setMinYValue(min.y - extra);
        setMaxYValue(max.y + extra);
    }

    private void drawSeries(Graphics g, DataSeries ds) {
        
        g.setColor(ds.getColor().intValue());

        Enumeration e = ds.points();
        DataPoint prev = null;
        int prevx = 0;
        int prevy = 0;

        Rectangle oldClip = setClipRect(g, chartRect);

        final double xUnitsPerPixel = (maxXValue - minXValue) / (double)chartRect.width();
        final double yUnitsPerPixel = (maxYValue - minYValue) / (double)chartRect.height();

        while (e.hasMoreElements()) {
            DataPoint pt = (DataPoint)e.nextElement();

            // point from value space to screen space.

            int x = (int)((pt.x - minXValue) / xUnitsPerPixel) + chartRect.left;
            int y = chartRect.bottom - (int)((pt.y - minYValue) / yUnitsPerPixel);

            if (dataPointsVisible)
                g.drawRect(x-1, y-1, 2, 2);

            if (prev != null)
                g.drawLine(x, y, prevx, prevy);

            prevx = x;
            prevy = y;
            prev = pt;

            // there is no point trying to draw the chart if we're already
            // outside the chart area
            if (x > chartRect.right)
                break;
        }

        setClipRect(g, oldClip);
    }

    /**
     * Set new clip rectangle
     * @param r
     * @return old clip rectangle.
     */
    private Rectangle setClipRect(Graphics g, Rectangle rc) {

        int l = g.getClipX();
        int t = g.getClipY();
        int b = t + g.getClipHeight();
        int r = l + g.getClipWidth();
        Rectangle res = new Rectangle(t, l, b, r);

        g.setClip(rc.left, rc.top, rc.width(), rc.height());

        return res;
    }

    public void showDataPoints() {
        dataPointsVisible = true;
    }

    public void hideDataPoints() {
        dataPointsVisible = false;
    }

    private Vector m_Series = new Vector();

    private double minXValue = 0.0;
    private double maxXValue = 180.0;
    private double minYValue = -10.0;
    private double maxYValue = 200.0;

    private final Rectangle chartRect;

    private boolean dataPointsVisible = true;
}
